<script lang="ts" setup>
import { addRuleAPI, deleteRuleAPI, editRuleAPI, getRuleListAPI, watchRuleAPI } from '@/apis/carRule';
import { ChargeType } from '@/enums/carRule';
import type { DurationParamsType, AddRuleParamsType, RuleItem, RuleListParams, TurnParamsType, PartitionParamsType } from '@/types/carRule';
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus';
import { ref } from 'vue';
import { utils, writeFileXLSX } from 'xlsx';

// 规则列表所需参数
const ruleParams = ref<RuleListParams>({
  page: 1,
  pageSize: 5
})

const ruleList = ref<RuleItem[]>([]) // 规则列表
const total = ref<number>(0) // 总条数
// 获取规则列表数据
const getRuleData = async () => {
  const res = await getRuleListAPI(ruleParams.value)
  total.value = res.data.total
  ruleList.value = res.data.rows
}
getRuleData()

// 计费方式
const chargeType = ref<{
  duration: string,
  turn: string,
  partition: string
}>({
  duration: '时长收费',
  turn: '按次收费',
  partition: '分段收费'
})

// 导出Excel
const exportToExcel = () => {
  // 1. 创建工作簿 (xlsx文件)  
  const workbook = utils.book_new()
  // 2. 创建工作表 (表格)
  const worksheet = utils.json_to_sheet(ruleList.value.map((item, index) => ({
    ...item,
    id: index + 1, // 把 id 覆盖成序号
    chargeCeiling: item.chargeCeiling || '--',
    chargeType: chargeType.value[item.chargeType] // 把 chargeType 覆盖成中文
  })))
  // 3. 往工作簿中添加表格 (工作簿, 表格, 表格名)
  utils.book_append_sheet(workbook, worksheet, '计费规则')
  // 4. 覆盖默认标题 (表格, 二维数组, 标题位置)
  utils.sheet_add_aoa(
    worksheet,
    // 二维数组
    [
      ['序号', '计费规则编号', '计费规则名称', '免费时长(分钟)', '收费上限(元)', '计费方式', '计费规则'],
    ],
    { origin: 'A1' }
  )
  // 4. 导出(下载) xlsx 文件
  writeFileXLSX(workbook, '停车计费规则.xlsx')
}

// 弹窗 - 添加 / 编辑 --------------------------
// 初始化计费规则数据 ------
const getDurationParams = (): DurationParamsType => {
  return {
    durationPrice: undefined, // 时长计费单位价格
    durationTime: undefined, // 时长计费单位时间
    durationType: undefined, // 时长收费,计费方式 ,minute分钟,hour:小时
  }
}
const getTurnParams = (): TurnParamsType => {
  return {
    turnPrice: undefined, // 按次收费：每次价格
  }
}
const getPartitionParams = (): PartitionParamsType => {
  return {
    partitionFramePrice: undefined, // 分段收费:段内费用
    partitionFrameTime: undefined, // 分段收费:段内时间
    partitionIncreasePrice: undefined, // 分段收费:超出范围收费价钱
    partitionIncreaseTime: undefined, // 分段收费:超出时间
  }
}

// 添加规则所需参数 ----------
const addRuleParams = ref<AddRuleParamsType>({
  chargeCeiling: undefined, // 收费上限
  chargeType: ChargeType.Duration, // 收费类型，时长收费:duration,按次收费:turn,分段收费:partition
  freeDuration: undefined, // 免费时长，单位:分钟
  ruleName: '', // 计费规则名称
  ruleNumber: '', // 计费规则编号
})
// 计费规则参数 -----------
const durationParams = ref<DurationParamsType>(getDurationParams())  // 时长收费参数
const turnParams = ref<TurnParamsType>(getTurnParams()) // 按次收费参数
const partitionParams = ref<PartitionParamsType>(getPartitionParams()) // 分段收费参数

// 表单实例
const addFormRef = ref<FormInstance>() // 添加表单实例
const durationFormRef = ref<FormInstance>() // 时长计费表单实例
const turnFormRef = ref<FormInstance>() // 按次收费表单实例
const partitionFormRef = ref<FormInstance>() // 分段收费表单实例

// 初始化全部计费规则函数 参数/校验
const initializeBillingRules = () => {
  // 重置表单
  durationParams.value = getDurationParams()
  partitionParams.value = getPartitionParams()
  turnParams.value = getTurnParams()
  // 清除表单校验
  durationFormRef.value?.resetFields()
  turnFormRef.value?.resetFields()
  partitionFormRef.value?.resetFields()
}

// Rule表单规则
const addRuleRules = ref<FormRules<AddRuleParamsType>>({
  ruleName: [
    { required: true, message: '请输入计费规则名称', trigger: 'blur' },
    { min: 2, max: 8, message: '长度在 2 到 8 个字符', trigger: 'blur' }
  ],
  chargeType: [
    { required: true, message: '请选择计费类型',trigger: 'change' }
  ],
  ruleNumber: [
    { required: true, message: '请输入计费规则编号', trigger: 'blur' },
    { min: 2, max: 8, message: '长度在 2 到 8 个字符', trigger: 'blur' }
  ]
})
// 时长计费表单规则
const durationRules = ref<FormRules<DurationParamsType>>({
  durationPrice: [
    { required: true, message: '请输入时长收费单价', trigger: 'blur' },
    { pattern: /^[0-9{.}]*$/, message: '请输入正数', trigger: 'blur' }
  ],
  durationTime: [
    { required: true, message: '请输入时长收费单位时间', trigger: 'blur' },
    { pattern: /^[0-9]*$/, message: '请输入正整数', trigger: 'blur' }
  ],
  durationType: [
    { required: true, message: '请选择时长计费单位', trigger: 'blur' },
  ]
})
// 按次收费表单规则
const turnRules = ref<FormRules<TurnParamsType>>({
  turnPrice: [
    { required: true, message: '请输入按次收费价格', trigger: 'blur' },
    { pattern: /^[0-9{.}]*$/, message: '请输入正数', trigger: 'blur' }
  ]
})
// 分段收费表单规则
const partitionRules = ref<FormRules<PartitionParamsType>>({
  partitionFramePrice: [
    { required: true, message: '请输入分段收费价格', trigger: 'blur' },
    { pattern: /^[0-9{.}]*$/, message: '请输入正数', trigger: 'blur' }
  ],
  partitionFrameTime: [
    { required: true, message: '请输入分段收费时间', trigger: 'blur' },
  ],
  partitionIncreasePrice: [
    { required: true, message: '请输入分段超出时间收费价格', trigger: 'blur' },
    { pattern: /^[0-9{.}]*$/, message: '请输入正数', trigger: 'blur' }
  ],
  partitionIncreaseTime: [
    { required: true, message: '请输入分段超出时间', trigger: 'blur' },
  ]
})

// 弹窗
const dialogVisible = ref(false) // 弹窗控制
// 开启弹窗
const openDialog = () => {
  dialogVisible.value = true
  editId.value = undefined // 重置编辑id
}
// 关闭弹窗
const closeDialog = () => {
  dialogVisible.value = false
  // 初始化所有数据 清除表单校验
  initializeBillingRules()
  addRuleParams.value = {
    chargeCeiling: undefined, // 收费上限
    chargeType: ChargeType.Duration, // 收费类型，时长收费:duration,按次收费:turn,分段收费:partition
    freeDuration: undefined, // 免费时长，单位:分钟
    ruleName: '', // 计费规则名称
    ruleNumber: '', // 计费规则编号
  }
  addFormRef.value?.resetFields()
}
// 收费类型切换
const chargeTypeChange = () => {
  initializeBillingRules()
}

// 编辑开启弹窗
const editId = ref<number | undefined>() // 编辑id
const editOpen = async (id:string) => {
  const res = await watchRuleAPI(id)
  // 打开弹窗
  openDialog()
  // 回显数据
  editId.value = res.data.id
  addRuleParams.value = {
    chargeCeiling: res.data.chargeCeiling,
    chargeType: res.data.chargeType,
    freeDuration: res.data.freeDuration,
    ruleName: res.data.ruleName,
    ruleNumber: res.data.ruleNumber
  }
  if (res.data.chargeType === ChargeType.Duration) {
    durationParams.value = {
      durationPrice: res.data.durationPrice,
      durationTime: res.data.durationTime,
      durationType: res.data.durationType
    }
  } else if (res.data.chargeType === ChargeType.Partition) {
    partitionParams.value = {
      partitionFramePrice: res.data.partitionFramePrice,
      partitionFrameTime: res.data.partitionFrameTime,
      partitionIncreasePrice: res.data.partitionIncreasePrice,
      partitionIncreaseTime: res.data.partitionIncreaseTime
    }
  } else if (res.data.chargeType === ChargeType.Turn) {
    turnParams.value = {
      turnPrice: res.data.turnPrice
    }
  }
}
// 统一校验所有表单函数 返回一个数组
const validateFormType = () => {
  const validateArr = [addFormRef.value?.validate()]
  if (addRuleParams.value.chargeType === ChargeType.Duration) {
    validateArr.push(durationFormRef.value?.validate())
  } else if (addRuleParams.value.chargeType === ChargeType.Turn) {
    validateArr.push(turnFormRef.value?.validate())
  } else if (addRuleParams.value.chargeType === ChargeType.Partition) {
    validateArr.push(partitionFormRef.value?.validate())
  }
  return validateArr
}
// 弹窗确认按钮 添加或编辑
const loadingFlag = ref(false)
const onConfirm = async () => {
  // 校验表单
  await Promise.all(validateFormType())

  loadingFlag.value = true

  try {
    if (!editId.value) {
      // 添加请求 
      await addRuleAPI({
        ...addRuleParams.value,
        ...durationParams.value,
        ...turnParams.value,
        ...partitionParams.value
      })
      ElMessage.success('添加成功')
    } else {
      // 编辑请求
      const res = await editRuleAPI({
        ...addRuleParams.value,
        ...durationParams.value,
        ...turnParams.value,
        ...partitionParams.value,
        id: editId.value!
      })
      
      if(res.code === 10000) {
        ElMessage.success('编辑成功')
      } else {
        ElMessage.error(res.msg)
      }
    }
  } finally {
    loadingFlag.value = false
  }

  // 完活
  getRuleData() // 刷新数据
  closeDialog() // 关闭弹窗
}

// 删除规则
const deleteRule = async (id: string) => {
  // 弹窗确认
  await ElMessageBox.confirm('确定删除吗？', '提示', {
    confirmButtonText: '确定',
    cancelButtonText: '取消',
    type: 'warning'
  })
  // 删除请求
  const res = await deleteRuleAPI(id)
  if(res.code === 10000) {
    ElMessage.success('删除成功')
  } else {
    ElMessage.error(res.msg)
  }
  getRuleData()
}
</script>

<template>
  <div class="rule-container">
    <div class="create-container">
      <el-button type="primary" @click="openDialog()" v-permission="'parking:rule:add_edit'">增加停车计费规则</el-button>
      <el-button @click="exportToExcel()">导出Excel</el-button>
    </div>
    <!-- 表格区域 -->
    <div class="table">
      <el-table :data="ruleList" style="width: 100%">
        <el-table-column type="index" label="序号" width="100" />
        <el-table-column label="计费规则编号" prop="ruleNumber" />
        <el-table-column label="计费规则名称" prop="ruleName" />
        <el-table-column label="免费时长(分钟)">
          <template #default="{ row }">
            {{ row.freeDuration || '--' }}
          </template>
        </el-table-column>
        <el-table-column label="收费上限(元)">
          <template #default="{ row }">
            {{ row.chargeCeiling || '--' }}
          </template>
        </el-table-column>
        <el-table-column label="计费方式">
          <template #default="{ row }">
            {{ chargeType[row.chargeType as RuleItem['chargeType']] }}
          </template>
        </el-table-column>
        <el-table-column label="计费规则" prop="ruleNameView" width="320" />
        <el-table-column label="操作" fixed="right" width="120">
          <template #default="{ row }">
            <el-button size="small" type="primary" link @click="editOpen(row.id)" v-permission="'parking:rule:add_edit'">编辑</el-button>
            <el-button size="small" type="primary" link @click="deleteRule(row.id)" v-permission="'parking:rule:remove'">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <!-- 分页 -->
    <div class="page-container">
      <el-pagination 
        layout="total, sizes, prev, pager, next"
        :total="total"
        :page-sizes="[2,5,10,20]"
        v-model:current-page="ruleParams.page" 
        v-model:page-size="ruleParams.pageSize"
        @change="getRuleData()"
      />
    </div>
    <!-- 添加/编辑弹窗 -->
    <el-dialog :title="!editId ? '添加合同' : '编辑合同'" v-model="dialogVisible" width="580px" @close="closeDialog()">
      <div class="form-container">
        <!-- 表单区域 -->
        <el-form ref="addFormRef" :model="addRuleParams" label-position="top" :rules="addRuleRules">
          <el-form-item label="计费规则编号" prop="ruleNumber">
            <el-input placeholder="请输入计费规则编号" v-model="addRuleParams.ruleNumber"></el-input>
          </el-form-item>
          <el-form-item label="计费规则名称" prop="ruleName">
            <el-input placeholder="请输入计费规则名称" v-model="addRuleParams.ruleName"></el-input>
          </el-form-item>
          <el-form-item label="计费方式（全天收费）" prop="chargeType">
            <div class="radio-group">
              <el-radio-group class="radio-group-list" v-model="addRuleParams.chargeType" @change="chargeTypeChange()">
                <el-radio value="duration" size="large" border>时长收费</el-radio>
                <el-radio value="turn" size="large" border>按次收费</el-radio>
                <el-radio value="partition" size="large" border>分段收费</el-radio>
              </el-radio-group>
            </div>
          </el-form-item>
          <!-- 免费时长 -->
          <el-form-item>
            <div class="mianfei-timer" label-position="top">
              <div class="left">
                <label>免费时长</label>
                <el-input v-model="addRuleParams.freeDuration" type="number" placeholder="请输入免费时长" style="margin-left: 0"></el-input>
              </div>
              <span>分</span>
              <span>钟</span>
              <div class="right">
                <label>收费上限</label>
                <el-input v-model="addRuleParams.chargeCeiling" type="number" placeholder="请输入收费上限"></el-input>
              </div>
              <span>元</span>
            </div>
          </el-form-item>
          <el-form-item label="计费规则" prop="inline">
            <!-- 时长收费 -->
            <el-form v-show="addRuleParams.chargeType === ChargeType.Duration" ref="durationFormRef":rules="durationRules" :model="durationParams" class="billing-rules">
              <span>每</span>
              <el-form-item prop="durationTime">
                <el-input type="number" placeholder="请输入" v-model="durationParams.durationTime"></el-input>
              </el-form-item>
              <el-form-item prop="durationType">
                <el-select v-model="durationParams.durationType" placeholder="请选择" style="width: 100px">
                  <el-option label="小时" value="hour" />
                  <el-option label="分钟" value="minute" />
                </el-select>
              </el-form-item>
              <el-form-item prop="durationPrice">
                <el-input placeholder="请输入" v-model="durationParams.durationPrice"></el-input>
              </el-form-item>
              <span>元</span>
            </el-form>
            <!-- 按次收费 -->
            <el-form v-show="addRuleParams.chargeType === ChargeType.Turn" ref="turnFormRef" :model="turnParams" :rules="turnRules" class="billing-rules">
              <span>每次</span>
              <el-form-item prop="turnPrice">
                <el-input v-model="turnParams.turnPrice" placeholder="请输入金额"></el-input>
              </el-form-item>
              <span>元</span>
            </el-form>
            <!-- 分段收费 -->
            <el-form v-show="addRuleParams.chargeType === ChargeType.Partition" :rules="partitionRules" ref="partitionFormRef" :model="partitionParams">
              <div class="partition-content">
                <el-form-item prop="partitionFrameTime">
                  <el-input type="number" placeholder="请输入" v-model="partitionParams.partitionFrameTime" style="margin-left: 0"></el-input>
                </el-form-item>
                <span>小时内，每小时收费</span>
                <el-form-item prop="partitionFramePrice">
                  <el-input placeholder="请输入" v-model="partitionParams.partitionFramePrice"></el-input>
                </el-form-item>
                <span>元</span>
              </div>
              <div class="partition-content">
                <span>每增加</span>
                <el-form-item prop="partitionIncreaseTime">
                  <el-input type="number" placeholder="请输入" v-model="partitionParams.partitionIncreaseTime"></el-input>
                </el-form-item>
                <span>小时，增加</span>
                <el-form-item prop="partitionIncreasePrice">
                  <el-input placeholder="请输入" v-model="partitionParams.partitionIncreasePrice"></el-input>
                </el-form-item>
                <span>元</span>
              </div>
            </el-form>
          </el-form-item>
        </el-form>
      </div>
      <template #footer>
        <el-button @click="closeDialog()">取 消</el-button>
        <el-button type="primary" @click="onConfirm()" :loading="loadingFlag">确 定</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<style lang="scss" scoped>
.radio-group {
  width: 100%;
  .radio-group-list {
    width: 100%;
    display: flex;
    .el-radio {
      padding: 10px;
    }
  }
}

.billing-rules {
  display: flex;
  gap: 10px;
}

.partition-content {
  display: flex;
  justify-content: space-between;
  .el-input {
    width: 109px;
    margin: 0 10px;
  }
  &:nth-child(1) {
    margin-bottom: 15px;
  }
}

.mianfei-timer {
  display: flex;
  align-items: end;
  .el-input {
    width: 160px;
    margin-left: 7px
  }
}

.rule-container {
  padding: 20px;
  background-color: #fff;
}

.rules .el-form-item {
  padding: 0 10px;
}

.search-container {
  display: flex;
  align-items: center;
  border-bottom: 1px solid rgb(237, 237, 237, .9);
  padding-bottom: 20px;

  .search-label {
    width: 100px;
  }

  .search-main {
    width: 220px;
    margin-right: 10px;
  }
}

.create-container {
  margin: 10px 0px;
}

.page-container {
  padding: 4px 0px;
  text-align: right;
}

.form-container {
  padding: 0px 80px;
}
</style>